package com.riwon.im.common.result;

import com.baomidou.mybatisplus.plugins.Page;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import static com.riwon.im.common.result.ResultData.Status.*;

/**
 * Created by keithfu on 15/12/3.
 * <p>
 * 注:如果前台调用接口时,有明确的数据校验,则后台(可能有特殊情况,另作讨论)不需要返回具体错误信息,只是参数异常即可.
 * Controller层通用JSON数据返回格式类
 */
public class ResultData extends HashMap<String, Object> {

    private static final long serialVersionUID = 1L;
    public static final String STATUS_KEY = "statusDes";
    public static final String STATUS_CODE = "status";
    public static final String STATUS_MSG = "statusMsg";
    private static final String NOWTIME = "nowTime";


    public enum Status implements ResponseStatus {

        SUCCESS(1, "OK"),
        FAILURE(0, "FAIL"),
        ERROR(500, "服务器异常");
        public final Integer code;
        public final String msg;

        Status(Integer code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        //将响应码注册至全局
        static {
            ResponseStatus.registStatus(Status.values());
        }

        @Override
        public Integer status() {
            return code;
        }

        @Override
        public String statusMsg() {
            return msg;
        }

        @Override
        public String statusDes() {
            return toString().toLowerCase();
        }
    }

    /**
     * 参数异常
     *
     * @return 当前实例
     */
    public ResultData parameterError() {
        this.setStatus(CommonRespStatus.PARAMETER_ERROR);
        return this;
    }

    /**
     * 参数异常
     *
     * @return 当前实例
     */
    public ResultData parameterError(String msg) {
        this.setStatus(CommonRespStatus.PARAMETER_ERROR);
        super.put(STATUS_MSG, msg);
        return this;
    }

    /**
     * 服务器忙
     *
     * @return 当前实例
     */
    public ResultData error() {
        this.setStatus(ERROR);
        return this;
    }

    /**
     * OK
     *
     * @return 当前实例
     */
    public ResultData success() {
        this.setStatus(SUCCESS);
        return this;
    }

    /**
     * FAILURE
     *
     * @return 当前实例
     */
    public ResultData failure() {
        this.setStatus(FAILURE);
        return this;
    }

    /**
     * 数据不存在
     *
     * @return 当前实例
     */
    public ResultData data404() {
        this.setStatus(CommonRespStatus.DATA404);
        return this;
    }


    public ResultData() {
        //默认设置为操作成功状态
        this.setStatus(SUCCESS);
        super.put(NOWTIME, new Date());
    }

    public Date getNowTime() {
        return (Date) get(NOWTIME);
    }

    /**
     * 设置响应状态
     *
     * @param status 状态对象
     * @return 当前实例
     */
    public ResultData setStatus(ResponseStatus status) {
        super.put(STATUS_KEY, status.statusDes());
        super.put(STATUS_CODE, status.status());
        super.put(STATUS_MSG, status.statusMsg());
        return this;
    }

    /**
     * 修改错误信息
     *
     * @param msg
     * @return
     */
    public ResultData changeMsg(String msg) {
        return this.put(STATUS_MSG, msg);
    }

    /**
     * 允许使用int类型设置响应状态码，此方法请谨慎使用。</br>
     *
     * @param status 响应码文档中所定义的code值
     * @return 响应码对应的Status对象, 如果状态码不存在，会产生IllegalArgumentException
     */
    public ResultData setStatus(Integer status) {
        this.setStatus(ResponseStatus.getStatusByCode(status));
        return this;
    }

    /**
     * 添加分页数据，调整为文档通用的解析格式
     *
     * @param page 分页数据对象
     * @return 实例本身
     */
    public ResultData parsePageBean(Page<?> page) {
        super.put("sEcho", "");
        super.put("iTotalRecords", page.getTotal());
        super.put("iTotalDisplayRecords", page.getRecords());
        super.put("aaData", page);
        return this;
    }

    /**
     * 分页数据,增加当前 查询时间
     *
     * @param page      分页数据
     * @param queryTime 分页查询时间
     * @return 通用响应对象
     */
    public ResultData parsePageBean(Page<?> page, Long queryTime) {
        parsePageBean(page);
        super.put("querytime", queryTime);
        return this;
    }

    /**
     * 添加列表数据（兼容分页数据），调整为文档通用的解析格式
     *
     * @param list 列表数据对象
     * @return 实例本身
     */
    @SuppressWarnings("rawtypes")
    public ResultData parseList(List<?> list) {
        if (list instanceof Page) {
            return parsePageBean((Page<?>) list);
        }
        super.put("sEcho", "");
        super.put("aaData", list == null ? new ArrayList() : list);
        return this;
    }

    /**
     * 对map数据的扩展，允许使用己有map进行数据填充
     *
     * @param map 外部map
     * @return 当前实例
     */
    public ResultData parseMap(Map<String, Object> map) {
        super.putAll(map);
        return this;
    }

    /**
     * 产生默认的构造实例，默认添加选中状态为
     *
     * @return 构造的实例
     */
    public static ResultData build() {
        return new ResultData();
    }

    /**
     * 添加自定义 数据
     *
     * @param key   key
     * @param value value
     * @return 当前实例
     */
    @Override
    public ResultData put(String key, Object value) {
        if (STATUS_CODE.equals(key)) {
            int code = NumberUtils.parseNumber(value.toString(), Integer.class);
            try {
                this.setStatus(ResponseStatus.getStatusByCode(code));
            } catch (Exception exception) {
                //status值不是存在时，清空原有的status_key与status_msg值
                super.put(STATUS_CODE, code);
                super.put(STATUS_KEY, "");
                super.put(STATUS_MSG, "");
            }
        } else {
            super.put(key, value);
        }
        return this;
    }

    /**
     * 不太建议使用的接口,此接口仅限于自定义code 及msg显示,key可为pw
     *
     * @param code 状态对应的CODE:如 100000
     * @param msg  状态对应的提示,如:登录验证失败
     * @param key  状态的英文名称,如 LOGIN_NEEDED ,可以为空,但建议最好带上一个值
     * @return
     */
    public ResultData put(Integer code, String msg, String key) {
        Assert.notNull(code, "状态不能为空");
        Assert.notNull(msg, "描述不能为空");
        super.put(STATUS_CODE, code);
        super.put(STATUS_KEY, key);
        super.put(STATUS_MSG, msg);
        return this;
    }

    /**
     * 将Bean 中的所有get方法的返回值,以方法名去除get后,首字母小写做为key,返回值为value存入当前 ResultData对象中
     *
     * @param object 各种Bean 如
     * @return
     */
    public ResultData parseBean(Object object) {

        Method[] methods = object.getClass().getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            Method method = methods[i];
            String name = method.getName();
            if (name.startsWith("get")) {
                try {
                    name = name.replaceAll("get", "");
                    name = name.replaceFirst(name.substring(0, 1), name.substring(0, 1).toLowerCase());
                    if (STATUS_CODE.equals(name)) {
                        name = "state";
                    }
                    super.put(name, method.invoke(object));
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return this;
    }

    /**
     * 检查状态码是否有重复的,如果有重复,报异常,阻止程序启动
     */
    public static void checkDevStatusOK() {
        CommonRespStatus.values();
        ResultData.Status.values();
    }
}
